home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Audio, Video & Photo / Songbird 0.7.0 / Songbird_0.7.0_windows-i686-msvc8.exe / jsmodules / sbAddToDevice.jsm < prev    next >
Text File  |  2008-08-06  |  16KB  |  543 lines

  1. /*
  2. //
  3. // BEGIN SONGBIRD GPL
  4. //
  5. // This file is part of the Songbird web player.
  6. //
  7. // Copyright(c) 2005-2008 POTI, Inc.
  8. // http://songbirdnest.com
  9. //
  10. // This file may be licensed under the terms of of the
  11. // GNU General Public License Version 2 (the "GPL").
  12. //
  13. // Software distributed under the License is distributed
  14. // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
  15. // express or implied. See the GPL for the specific language
  16. // governing rights and limitations.
  17. //
  18. // You should have received a copy of the GPL along with this
  19. // program. If not, go to http://www.gnu.org/licenses/gpl.html
  20. // or write to the Free Software Foundation, Inc.,
  21. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. //
  23. // END SONGBIRD GPL
  24. //
  25.  */
  26.  
  27. Components.utils.import("resource://app/jsmodules/sbProperties.jsm");
  28. Components.utils.import("resource://app/jsmodules/DropHelper.jsm");
  29.  
  30. const Ci = Components.interfaces;
  31.  
  32. const ADDTODEVICE_MENU_TYPE      = "submenu";
  33. const ADDTODEVICE_MENU_ID        = "library_cmd_addtodevice";
  34. const ADDTODEVICE_MENU_NAME      = "&command.addtodevice";
  35. const ADDTODEVICE_MENU_TOOLTIP   = "&command.tooltip.addtodevice";
  36. const ADDTODEVICE_MENU_KEY       = "&command.shortcut.key.addtodevice";
  37. const ADDTODEVICE_MENU_KEYCODE   = "&command.shortcut.keycode.addtodevice";
  38. const ADDTODEVICE_MENU_MODIFIERS = "&command.shortcut.modifiers.addtodevice";
  39.  
  40.  
  41. const ADDTODEVICE_COMMAND_ID = "library_cmd_addtodevice:";
  42.  
  43. EXPORTED_SYMBOLS = [ "addToDeviceHelper",
  44.                      "SBPlaylistCommand_AddToDevice" ];
  45.  
  46. // ----------------------------------------------------------------------------
  47. // The "Add to device" dynamic command object
  48. // ----------------------------------------------------------------------------
  49. var SBPlaylistCommand_AddToDevice =
  50. {
  51.   m_Context: {
  52.     m_Playlist: null,
  53.     m_Window: null
  54.   },
  55.  
  56.   m_addToDevice: null,
  57.  
  58.   m_root_commands :
  59.   {
  60.     m_Types: new Array
  61.     (
  62.       ADDTODEVICE_MENU_TYPE
  63.     ),
  64.  
  65.     m_Ids: new Array
  66.     (
  67.       ADDTODEVICE_MENU_ID
  68.     ),
  69.  
  70.     m_Names: new Array
  71.     (
  72.       ADDTODEVICE_MENU_NAME
  73.     ),
  74.  
  75.     m_Tooltips: new Array
  76.     (
  77.       ADDTODEVICE_MENU_TOOLTIP
  78.     ),
  79.  
  80.     m_Keys: new Array
  81.     (
  82.       ADDTODEVICE_MENU_KEY
  83.     ),
  84.  
  85.     m_Keycodes: new Array
  86.     (
  87.       ADDTODEVICE_MENU_KEYCODE
  88.     ),
  89.  
  90.     m_Enableds: new Array
  91.     (
  92.       true
  93.     ),
  94.  
  95.     m_Modifiers: new Array
  96.     (
  97.       ADDTODEVICE_MENU_MODIFIERS
  98.     ),
  99.  
  100.     m_PlaylistCommands: new Array
  101.     (
  102.       null
  103.     )
  104.   },
  105.  
  106.   _getMenu: function(aSubMenu)
  107.   {
  108.     var cmds;
  109.  
  110.     cmds = this.m_addToDevice.handleGetMenu(aSubMenu);
  111.     if (cmds) return cmds;
  112.  
  113.     switch (aSubMenu) {
  114.       default:
  115.         cmds = this.m_root_commands;
  116.         break;
  117.     }
  118.     return cmds;
  119.   },
  120.  
  121.   getVisible: function( aHost )
  122.   {
  123.     return this.m_addToDevice.hasDevices();
  124.   },
  125.  
  126.   getNumCommands: function( aSubMenu, aHost )
  127.   {
  128.     var cmds = this._getMenu(aSubMenu);
  129.     return cmds.m_Ids.length;
  130.   },
  131.  
  132.   getCommandId: function( aSubMenu, aIndex, aHost )
  133.   {
  134.     var cmds = this._getMenu(aSubMenu);
  135.     if ( aIndex >= cmds.m_Ids.length ) return "";
  136.     return cmds.m_Ids[ aIndex ];
  137.   },
  138.  
  139.   getCommandType: function( aSubMenu, aIndex, aHost )
  140.   {
  141.     var cmds = this._getMenu(aSubMenu);
  142.     if ( aIndex >= cmds.m_Ids.length ) return "";
  143.     return cmds.m_Types[ aIndex ];
  144.   },
  145.  
  146.   getCommandText: function( aSubMenu, aIndex, aHost )
  147.   {
  148.     var cmds = this._getMenu(aSubMenu);
  149.     if ( aIndex >= cmds.m_Names.length ) return "";
  150.     return cmds.m_Names[ aIndex ];
  151.   },
  152.  
  153.   getCommandFlex: function( aSubMenu, aIndex, aHost )
  154.   {
  155.     var cmds = this._getMenu(aSubMenu);
  156.     if ( cmds.m_Types[ aIndex ] == "separator" ) return 1;
  157.     return 0;
  158.   },
  159.  
  160.   getCommandToolTipText: function( aSubMenu, aIndex, aHost )
  161.   {
  162.     var cmds = this._getMenu(aSubMenu);
  163.     if ( aIndex >= cmds.m_Tooltips.length ) return "";
  164.     return cmds.m_Tooltips[ aIndex ];
  165.   },
  166.  
  167.   getCommandValue: function( aSubMenu, aIndex, aHost )
  168.   {
  169.   },
  170.  
  171.   instantiateCustomCommand: function( aDocument, aId, aHost )
  172.   {
  173.     return null;
  174.   },
  175.  
  176.   refreshCustomCommand: function( aElement, aId, aHost )
  177.   {
  178.   },
  179.  
  180.   getCommandVisible: function( aSubMenu, aIndex, aHost )
  181.   {
  182.     return true;
  183.   },
  184.  
  185.   getCommandFlag: function( aSubmenu, aIndex, aHost )
  186.   {
  187.     return false;
  188.   },
  189.  
  190.   getCommandChoiceItem: function( aChoiceMenu, aHost )
  191.   {
  192.     return "";
  193.   },
  194.  
  195.   getCommandEnabled: function( aSubMenu, aIndex, aHost )
  196.   {
  197.     if (this.m_Context.m_Playlist.tree.currentIndex == -1) return false;
  198.     var cmds = this._getMenu(aSubMenu);
  199.     return cmds.m_Enableds[ aIndex ];
  200.   },
  201.  
  202.   getCommandShortcutModifiers: function ( aSubMenu, aIndex, aHost )
  203.   {
  204.     var cmds = this._getMenu(aSubMenu);
  205.     if ( aIndex >= cmds.m_Modifiers.length ) return "";
  206.     return cmds.m_Modifiers[ aIndex ];
  207.   },
  208.  
  209.   getCommandShortcutKey: function ( aSubMenu, aIndex, aHost )
  210.   {
  211.     var cmds = this._getMenu(aSubMenu);
  212.     if ( aIndex >= cmds.m_Keys.length ) return "";
  213.     return cmds.m_Keys[ aIndex ];
  214.   },
  215.  
  216.   getCommandShortcutKeycode: function ( aSubMenu, aIndex, aHost )
  217.   {
  218.     var cmds = this._getMenu(aSubMenu);
  219.     if ( aIndex >= cmds.m_Keycodes.length ) return "";
  220.     return cmds.m_Keycodes[ aIndex ];
  221.   },
  222.  
  223.   getCommandShortcutLocal: function ( aSubMenu, aIndex, aHost )
  224.   {
  225.     return true;
  226.   },
  227.  
  228.   getCommandSubObject: function ( aSubMenu, aIndex, aHost )
  229.   {
  230.     var cmds = this._getMenu(aSubMenu);
  231.     if ( aIndex >= cmds.m_PlaylistCommands.length ) return null;
  232.     return cmds.m_PlaylistCommands[ aIndex ];
  233.   },
  234.  
  235.   onCommand: function( aSubMenu, aIndex, aHost, id, value )
  236.   {
  237.     if ( id )
  238.     {
  239.       // ADDTODEVICE
  240.       if (this.m_addToDevice.handleCommand(id)) return;
  241.  
  242.       // ...
  243.     }
  244.   },
  245.  
  246.   // The object registered with the sbIPlaylistCommandsManager interface acts
  247.   // as a template for instances bound to specific playlist elements
  248.  
  249.   dupObject: function (obj) {
  250.     var r = {};
  251.     for ( var i in obj )
  252.     {
  253.       r[ i ] = obj[ i ];
  254.     }
  255.     return r;
  256.   },
  257.  
  258.   duplicate: function()
  259.   {
  260.     var obj = this.dupObject(this);
  261.     obj.m_Context = this.dupObject(this.m_Context);
  262.     return obj;
  263.   },
  264.  
  265.   initCommands: function(aHost) {
  266.     this.m_addToDevice = new addToDeviceHelper();
  267.     this.m_addToDevice.init(this);
  268.   },
  269.  
  270.   shutdownCommands: function() {
  271.     if (!this.m_addToDevice) {
  272.       dump("this.m_addToDevice is null in SBPlaylistCommand_AddToDevice ?!!\n");
  273.       return;
  274.     }
  275.     this.m_addToDevice.shutdown();
  276.     this.m_addToDevice = null;
  277.     this.m_Context = null;
  278.   },
  279.  
  280.   setContext: function( context )
  281.   {
  282.     var playlist = context.playlist;
  283.     var window = context.window;
  284.  
  285.     // Ah.  Sometimes, things are being secure.
  286.  
  287.     if ( playlist && playlist.wrappedJSObject )
  288.       playlist = playlist.wrappedJSObject;
  289.  
  290.     if ( window && window.wrappedJSObject )
  291.       window = window.wrappedJSObject;
  292.  
  293.     this.m_Context.m_Playlist = playlist;
  294.     this.m_Context.m_Window = window;
  295.   },
  296.  
  297.   QueryInterface : function(aIID)
  298.   {
  299.     if (!aIID.equals(Components.interfaces.sbIPlaylistCommands) &&
  300.         !aIID.equals(Components.interfaces.nsISupportsWeakReference) &&
  301.         !aIID.equals(Components.interfaces.nsISupports))
  302.     {
  303.       throw Components.results.NS_ERROR_NO_INTERFACE;
  304.     }
  305.  
  306.     return this;
  307.   }
  308. }; // SBPlaylistCommand_AddToDevice declaration
  309.  
  310. function addToDeviceHelper() {
  311. }
  312.  
  313. addToDeviceHelper.prototype = {
  314.   m_listofdevices: null,
  315.   m_commands: null,
  316.   m_deviceManager: null,
  317.   m_libraryManager: null,
  318.  
  319.   LOG: function(str) {
  320.     var consoleService = Components.classes['@mozilla.org/consoleservice;1']
  321.                             .getService(Components.interfaces.nsIConsoleService);
  322.     consoleService.logStringMessage(str);
  323.   },
  324.  
  325.   init: function addToDeviceHelper_init(aCommands) {
  326.     this.m_libraryManager = 
  327.       Components.classes["@songbirdnest.com/Songbird/library/Manager;1"]
  328.       .getService(Components.interfaces.sbILibraryManager);
  329.     this.m_deviceManager = 
  330.       Components.classes["@songbirdnest.com/Songbird/DeviceManager;2"]
  331.       .getService(Components.interfaces.sbIDeviceManager2);
  332.     var eventTarget = 
  333.       this.m_deviceManager.QueryInterface(
  334.         Components.interfaces.sbIDeviceEventTarget
  335.       );
  336.     eventTarget.addEventListener(this);
  337.     this.m_commands = aCommands;
  338.     this.makeListOfDevices();
  339.   },
  340.  
  341.   shutdown: function addToDeviceHelper_shutdown() {
  342.     var eventTarget = 
  343.       this.m_deviceManager.QueryInterface(
  344.         Components.interfaces.sbIDeviceEventTarget
  345.       );
  346.     eventTarget.removeEventListener(this);
  347.     this.m_deviceManager = null;
  348.   },
  349.  
  350.   // returns true if we have at least one device in the list,
  351.   // the commands object hides the "add to device" submenu when
  352.   // no device is present  
  353.   hasDevices: function addToDeviceHelper_hasDevices() {
  354.     return (this.m_listofdevices &&
  355.             this.m_listofdevices.m_Types &&
  356.             this.m_listofdevices.m_Types.length > 0);
  357.   },
  358.  
  359.   // builds the list of devices, called on startup and when a
  360.   // device is added or removed
  361.   makeListOfDevices: function addToDeviceHelper_makeListOfDevices() {
  362.     this._makingList = true;
  363.  
  364.     this.m_listofdevices = {};
  365.     this.m_listofdevices.m_Types = new Array();
  366.     this.m_listofdevices.m_Ids = new Array();
  367.     this.m_listofdevices.m_Names = new Array();
  368.     this.m_listofdevices.m_Tooltips = new Array();
  369.     this.m_listofdevices.m_Enableds = new Array();
  370.     this.m_listofdevices.m_Modifiers = new Array();
  371.     this.m_listofdevices.m_Keys = new Array();
  372.     this.m_listofdevices.m_Keycodes = new Array();
  373.     this.m_listofdevices.m_PlaylistCommands = new Array();
  374.     
  375.     // get all devices
  376.     var registrar = 
  377.       this.m_deviceManager.QueryInterface(
  378.         Components.interfaces.sbIDeviceRegistrar
  379.       );
  380.     var devices = Array();
  381.     // turn into a js array
  382.     for (var i=0;i<registrar.devices.length;i++) {
  383.       var device = registrar.devices.queryElementAt
  384.                                        (i, Components.interfaces.sbIDevice);
  385.       if (device && device.connected)
  386.         devices.push(device);
  387.     }
  388.     // order of devices returned by the registrar is undefined, 
  389.     // so sort by device friendly name
  390.     function deviceSorter(x, y) {
  391.       var friendlyNameX = x.properties.friendlyName;
  392.       var friendlyNameY = y.properties.friendlyName;
  393.       if (x < y) return -1;
  394.       if (y < x) return 1;
  395.       return 0;
  396.     }
  397.     devices.sort(deviceSorter);
  398.     // extract the device names and associated library guids
  399.     // and fill the arrays used by the command object
  400.     for (var d in devices) {
  401.       var libraryguid;
  402.       var device = devices[d];
  403.       var devicename = device.properties.friendlyName;
  404.       var isEnabled = false;
  405.       if (!devicename) 
  406.         devicename = "Unnamed Device";
  407.       if (device.content && device.content.libraries.length > 0) {
  408.         var library = device.content.libraries.
  409.           queryElementAt(0, Components.interfaces.sbILibrary);
  410.         isEnabled = library.userEditable;
  411.         libraryguid = library.guid;
  412.       } else {
  413.         continue;
  414.       }
  415.       this.m_listofdevices.m_Types.push("action");
  416.       this.m_listofdevices.m_Ids.push(ADDTODEVICE_COMMAND_ID + 
  417.                                       libraryguid + ";" + 
  418.                                       devicename);
  419.       this.m_listofdevices.m_Names.push(devicename);
  420.       this.m_listofdevices.m_Tooltips.push(devicename);
  421.       this.m_listofdevices.m_Enableds.push(isEnabled);
  422.       this.m_listofdevices.m_Modifiers.push("");
  423.       this.m_listofdevices.m_Keys.push("");
  424.       this.m_listofdevices.m_Keycodes.push("");
  425.       this.m_listofdevices.m_PlaylistCommands.push(null);
  426.     }
  427.  
  428.     this._makingList = false;
  429.   },
  430.  
  431.   handleGetMenu: function addToDeviceHelper_handleGetMenu(aSubMenu) {
  432.     if (this.m_listofdevices == null) {
  433.       // handleGetMenu called before makeListOfPlaylists, this would 
  434.       // cause infinite recursion : the command object would not find
  435.       // the menu either, would return null to getMenu which corresponds
  436.       // to the root menu, and it'd recurse infinitly.
  437.       throw Components.results.NS_ERROR_FAILURE;
  438.     }
  439.     if (aSubMenu == ADDTODEVICE_MENU_ID) return this.m_listofdevices;
  440.     return null;
  441.   },
  442.  
  443.   // handle click on a device command item
  444.   handleCommand: function addToDeviceHelper_handleCommand(id) {
  445.     try {
  446.       var context = this.m_commands.m_Context;
  447.       var addtodevicestr = ADDTODEVICE_COMMAND_ID;
  448.       if ( id.slice(0, addtodevicestr.length) == addtodevicestr) {
  449.         var r = id.slice(addtodevicestr.length);
  450.         var parts = r.split(';');
  451.         if (parts.length >= 2) {
  452.           var libraryguid = parts[0];
  453.           var devicename = parts[1];
  454.           this.addToDevice(libraryguid, context.m_Playlist, devicename);
  455.           return true;
  456.         }
  457.       }
  458.     } catch (e) {
  459.       Components.utils.reportError(e);
  460.     }
  461.     return false;
  462.   },
  463.  
  464.   // perform the transfer of the selected items to the device library
  465.   addToDevice: function addToDeviceHelper_addToDevice(
  466.                           devicelibraryguid, 
  467.                           sourceplaylist, 
  468.                           devicename) {
  469.     var library = this.m_libraryManager.getLibrary(devicelibraryguid);
  470.     if (library) {
  471.       var oldLength = library.length;
  472.       var selection = 
  473.         sourceplaylist.mediaListView.selection.selectedIndexedMediaItems;
  474.  
  475.       // Create an enumerator that wraps the enumerator we were handed since
  476.       // the enumerator we get hands back sbIIndexedMediaItem, not just plain
  477.       // 'ol sbIMediaItems
  478.  
  479.       var unwrapper = {
  480.         enumerator: selection,
  481.  
  482.         hasMoreElements : function() {
  483.           return this.enumerator.hasMoreElements();
  484.         },
  485.         getNext : function() {
  486.           var item = this.enumerator.getNext().mediaItem;
  487.           item.setProperty(SBProperties.downloadStatusTarget,
  488.                            item.library.guid + "," + item.guid);
  489.           return item;
  490.         },
  491.         QueryInterface : function(iid) {
  492.           if (iid.equals(Components.interfaces.nsISimpleEnumerator) ||
  493.               iid.equals(Components.interfaces.nsISupports))
  494.             return this;
  495.           throw Components.results.NS_NOINTERFACE;
  496.         }
  497.       }
  498.  
  499.       library.addSome(unwrapper);
  500.  
  501.       var added = library.length - oldLength;
  502.       DNDUtils.reportAddedTracks(added, 0, devicename);
  503.     }
  504.   },
  505.  
  506.   //-----------------------------------------------------------------------------
  507.   // methods for refreshing the list when needed, detection is performed via
  508.   // an sbIDeviceEventListener on the device manager
  509.   //-----------------------------------------------------------------------------
  510.   
  511.   _makingList    : false,
  512.  
  513.   refreshCommands: function addToDeviceHelper_refreshCommands() {
  514.     if (this.m_commands) {
  515.       if (this.m_commands.m_Context && this.m_commands.m_Context.m_Playlist) {
  516.         this.makeListOfDevices();
  517.         this.m_commands.m_Context.m_Playlist.refreshCommands();
  518.       }
  519.     }
  520.   },
  521.  
  522.   onUpdateEvent: function addToDeviceHelper_onUpdateEvent() {
  523.     if (this._makingList) return;
  524.     this.refreshCommands();
  525.   },
  526.  
  527.   QueryInterface: function QueryInterface(iid) {
  528.     if (!iid.equals(Components.interfaces.sbIDeviceEventListener) &&
  529.         !iid.equals(Components.interfaces.nsISupports))
  530.       throw Components.results.NS_ERROR_NO_INTERFACE;
  531.     return this;
  532.   },
  533.   
  534.   // trap event for device added/removed, and refresh the commands
  535.   onDeviceEvent: function addToDeviceHelper_onDeviceEvent(aEvent) {
  536.     if (aEvent.type == Components.interfaces.sbIDeviceEvent.EVENT_DEVICE_ADDED ||
  537.         aEvent.type == Components.interfaces.sbIDeviceEvent.EVENT_DEVICE_REMOVED) {
  538.       this.onUpdateEvent();
  539.     }
  540.   }
  541.  
  542. };
  543.